#include "stdafx.h"
#include "base/thread/ThreadMgr.h"
#include "base/thread/MessageLoopForUI.h"

namespace xBase
{
    template<>
    class TxSingleton<CxThreadMgr>
    {};

    CxThreadMgr::CxThreadMgr()
    {
    }

    CxThreadMgr::~CxThreadMgr()
    {
    }

    BOOL CxThreadMgr::AttachThread(DWORD dwThreadId, LOOP_TYPE type, std::string strDescription)
    {
        ThreadDataMap::iterator it = m_mapThreadData.find(dwThreadId);
        if (it != m_mapThreadData.end())
            return FALSE;

        ThreadData data;
        data.type = type;
        data.strDescription = strDescription;
        switch (type)
        {
        case LOOP_TYPE_UI:
            {
                data.pMsgLoop = new CxMessageLoopForUI;
            }
            break;
        case LOOP_TYPE_DEFAULT:
        case LOOP_TYPE_IO:
        default:
            break;
        }

        m_mapThreadData.insert(std::make_pair(dwThreadId, data));

        return TRUE;
    }

    BOOL CxThreadMgr::DetachThread(DWORD dwThreadId)
    {
        ThreadDataMap::iterator it = m_mapThreadData.find(dwThreadId);
        if (it != m_mapThreadData.end())
        {
            ThreadData & td = it->second;
            if (td.bAttach)
            {
                delete td.pMsgLoop;
                m_mapThreadData.erase(it);
                return TRUE;
            }
        }
        return FALSE;
    }

    BOOL CxThreadMgr::RunMessageLoop()
    {
        ThreadDataMap::iterator it = m_mapThreadData.find(::GetCurrentThreadId());
        if (it != m_mapThreadData.end())
        {
            CxMessageLoop* pLoop = (it->second).pMsgLoop;
            if (pLoop)
            {
                pLoop->RunWithDispatcher(NULL);
                return TRUE;
            }
        }
        return FALSE;
    }

    BOOL CxThreadMgr::PostTask(INT nType,CTask* pTask, INT64 delay)
    {
        return TRUE;
    }

    BOOL CxThreadMgr::PostTaskByThreadId(DWORD dwThreadId, CTask* pTask, INT64 delay)
    {
        return TRUE;
    }

    BOOL CxThreadMgr::StartThread(LPCSTR name, LOOP_TYPE type, DWORD* pTid)
    {
        if (!pTid)
        {
            assert(false);
            return FALSE;
        }

        CxThread* th = new (std::nothrow) CxThread(name);

        if (!th)
        {
            assert(!"new CxThread failure");
            return FALSE;
        }

        CxThread::CxOptions topt;
        topt.m_eMessageLoopType = type;

        BOOL bRet = th->StartWithOptions(topt);

        *pTid = th->GetThreadID();

        ThreadData data;
        data.dwThreadId     = *pTid;
        data.pThread        = th;
        data.pMsgLoop       = th->GetMessageLoop();
        th->GetMessageLoopProxy(data.pMsgLoopProxy);

        m_olock.Acquire();
        m_mapThreadData.insert(std::make_pair(data.dwThreadId, data));
        m_olock.Release();

        return S_OK;
    }

    BOOL CxThreadMgr::StopThread(DWORD tid)
    {
        CxThread* th = NULL;

        {
            m_olock.Acquire();

            ThreadDataMap::iterator it = m_mapThreadData.find(tid);

            if (it != m_mapThreadData.end())
            {
                th = it->second.pThread;
                m_mapThreadData.erase(it);
            }

            m_olock.Release();
        }


        if (!th)
        {
            return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
        }

        HRESULT hr = th->Stop();
        delete th;
        return hr;
    }
}